package com.fun.widget.tag.core;

import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.widget.ViewDragHelper;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.fun.widget.tag.TagsView;
import com.fun.widget.tag.event.OnTagItemClickListener;
import com.fun.widget.tag.event.OnTagItemLongClickListener;

/**
 * @author Created by AdminFun
 * @version v1.0.0
 * @date 2019/10/9 18:50
 * 标签的ItemView，利用builder来构建样式
 */
public class TagItemView extends View {

    /**
     * 标签样式构建器，每一个标签对应一个构建器
     */
    private TagStyleBuilder styleBuilder;

    /**
     * 标签的点击事件
     */
    private OnTagItemLongClickListener onTagItemLongClickListener;

    /**
     * 标签长按事件
     */
    private OnTagItemClickListener onTagItemClickListener;

    /**
     * 标签的父容器所处的position（仅在列表中使用标签时可用）
     */
    private int mCurrentParentId = 0;

    private int mMoveSlop = 5;
    private int mSlopThreshold = 4;
    private Paint mPaint, mRipplePaint;
    private RectF mRectF;
    private String mAbstractText, mOriginText;
    private boolean isUp, isMoved, isExecLongClick;
    private int mLastX, mLastY;
    private float fontH, fontW;
    private float mTouchX, mTouchY;
    private Path mPath;
    private boolean unSupportedClipPath = false;

    private Runnable mLongClickHandle = new Runnable() {

        @Override
        public void run() {
            if (!isMoved && !isUp) {
                int state = ((TagsView) getParent()).getTagViewState();
                if (state == ViewDragHelper.STATE_IDLE) {
                    isExecLongClick = true;
                    if (onTagItemLongClickListener != null) {
                        onTagItemLongClickListener.onTagLongClick(mCurrentParentId, (int) getTag(), getText());
                    }
                }
            }
        }
    };

    public TagItemView(Context context) {
        super(context);
        this.initViews(context);
    }

    public TagItemView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.initViews(context);
    }

    public TagItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.initViews(context);
    }

    private void initViews(Context context) {
        this.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.mRipplePaint.setStyle(Paint.Style.FILL);
        this.mRectF = new RectF();
        this.mPath = new Path();
        this.mMoveSlop = ScreenUtils.dip2px(context, mMoveSlop);
        this.mSlopThreshold = ScreenUtils.dip2px(context, mSlopThreshold);
    }

    /**
     * 设置标签文本
     */
    public void setText(String text) {
        this.mOriginText = text == null ? "" : text;
    }

    /**
     * 配置标签样式构建器
     * 配置构建器后需要重新绘制UI（把之前绘制的方法集中到一块来绘制）
     */
    public void setStyleBuilder(@NonNull TagStyleBuilder styleBuilder) {
        this.styleBuilder = styleBuilder;
        this.styleBuilder.build();
        this.onDealText();
    }

    /**
     * 检查样式构建器
     */
    public boolean checkStyleBuilderNull() {
        if (styleBuilder == null) {
            Log.d("common", "请确认每一个标签都已经配置了1个样式构建器！");
            return false;
        }
        return true;
    }

    /**
     * 设置标签长按事件
     */
    public void setOnTagItemLongClickListener(OnTagItemLongClickListener onTagItemLongClickListener) {
        this.onTagItemLongClickListener = onTagItemLongClickListener;
    }

    /**
     * 设置标签点击事件
     */
    public void setOnTagItemClickListener(OnTagItemClickListener onTagItemClickListener) {
        this.onTagItemClickListener = onTagItemClickListener;
    }

    /**
     * 设置父容器的ID
     */
    public void setCurrentParentId(int mParentId) {
        this.mCurrentParentId = mParentId;
    }

    public String getText() {
        return mOriginText;
    }

    private void onDealText() {
        if (checkStyleBuilderNull()) {
            if (!TextUtils.isEmpty(mOriginText)) {
                final int mTagMaxLength = styleBuilder.getTagMaxLength();
                this.mAbstractText = mOriginText.length() <= mTagMaxLength ?
                        mOriginText : mOriginText.substring(0, mTagMaxLength) + "..";
            } else {
                this.mAbstractText = "";
            }

            this.mPaint.setTypeface(styleBuilder.getTypeface());
            this.mPaint.setTextSize(styleBuilder.getTextSize());
            final Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
            this.fontH = fontMetrics.descent - fontMetrics.ascent;
            this.fontW = mPaint.measureText(mAbstractText);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (checkStyleBuilderNull()) {
            int height = styleBuilder.getVerticalPadding() * 2 + (int) fontH;
            int width = styleBuilder.getHorizontalPadding() * 2 + (int) fontW;
            this.setMeasuredDimension(width, height);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (checkStyleBuilderNull()) {
            float mBorderWidth = styleBuilder.getBorderWidth();
            this.mRectF.set(mBorderWidth, mBorderWidth, w - mBorderWidth, h - mBorderWidth);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (checkStyleBuilderNull()) {
            // 绘制背景
            this.mPaint.setStyle(Paint.Style.FILL);
            this.mPaint.setColor(styleBuilder.getBackgroundColor());
            canvas.drawRoundRect(mRectF, styleBuilder.getBorderRadius(), styleBuilder.getBorderRadius(), mPaint);

            // 绘制边框
            this.mPaint.setStyle(Paint.Style.STROKE);
            this.mPaint.setStrokeWidth(styleBuilder.getBorderWidth());
            this.mPaint.setColor(styleBuilder.getBorderColor());
            if (styleBuilder.isFillLine()) {
                this.mPaint.setPathEffect(null);
            } else {
                this.mPaint.setPathEffect(styleBuilder.getPathEffect());
            }
            canvas.drawRoundRect(mRectF, styleBuilder.getBorderRadius(), styleBuilder.getBorderRadius(), mPaint);

            // 绘制水波纹效果
            drawRipple(canvas);

            // 绘制文本
            this.mPaint.setStyle(Paint.Style.FILL);
            this.mPaint.setColor(styleBuilder.getTextColor());

            final int tempWidth = this.getWidth();
            final int tempHeight = this.getHeight();
            canvas.drawText(mAbstractText,
                    ((float) (tempWidth / 2)) - fontW / 2,
                    ((float) (tempHeight / 2)) + fontH / 2 - styleBuilder.getDistanceBaseLine(),
                    mPaint);
        }
    }

    /**
     * 绘制水波纹效果
     */
    private void drawRipple(@NonNull Canvas canvas) {
        if (!unSupportedClipPath && styleBuilder != null) {
            try {
                canvas.save();
                mPath.reset();
                canvas.clipPath(mPath);
                mPath.addRoundRect(mRectF, styleBuilder.getBorderRadius(),
                        styleBuilder.getBorderRadius(), Path.Direction.CCW);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    canvas.clipPath(mPath);
                } else {
                    canvas.clipPath(mPath, Region.Op.REPLACE);
                }
                canvas.drawCircle(mTouchX, mTouchY, styleBuilder.getRippleRadius(), mRipplePaint);
                canvas.restore();
            } catch (UnsupportedOperationException e) {
                unSupportedClipPath = true;
            }
        }
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        int x = (int) event.getX();
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (getParent() != null) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                mLastY = y;
                mLastX = x;
                break;

            case MotionEvent.ACTION_MOVE:
                if ((Math.abs(mLastY - y) > mSlopThreshold || Math.abs(mLastX - x) > mSlopThreshold)) {
                    if (getParent() != null) {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }
                    isMoved = true;
                    return false;
                }
                break;

            default:
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (checkStyleBuilderNull()) {
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN) {
                styleBuilder.setRippleRadius(0);
                mTouchX = event.getX();
                mTouchY = event.getY();
                splashRipple(styleBuilder);
            }

            if (onTagItemClickListener != null) {
                int x = (int) event.getX();
                int y = (int) event.getY();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        mLastY = y;
                        mLastX = x;
                        isMoved = false;
                        isUp = false;
                        isExecLongClick = false;
                        postDelayed(mLongClickHandle, styleBuilder.getLongPressTime());
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (isMoved) {
                            break;
                        }
                        if (Math.abs(mLastX - x) > mMoveSlop || Math.abs(mLastY - y) > mMoveSlop) {
                            isMoved = true;
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                        isUp = true;
                        if (!isExecLongClick && !isMoved) {
                            onTagItemClickListener.onTagClick(mCurrentParentId, (int) getTag(), getText());
                        }
                        break;

                    default:
                        break;
                }
                return true;
            }
        }
        return super.onTouchEvent(event);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void splashRipple(@NonNull TagStyleBuilder builder) {
        if (mTouchX > 0 && mTouchY > 0) {
            mRipplePaint.setColor(builder.getRippleColor());
            mRipplePaint.setAlpha(builder.getRippleAlpha());
            final float maxDis = Math.max(Math.max(Math.max(mTouchX, mTouchY),
                    Math.abs(getMeasuredWidth() - mTouchX)),
                    Math.abs(getMeasuredHeight() - mTouchY));

            ValueAnimator mRippleValueAnimator = ValueAnimator.ofFloat(0.0f, maxDis).setDuration(builder.getRippleDuration());
            mRippleValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float animValue = (float) animation.getAnimatedValue();
                    if (styleBuilder != null) {
                        styleBuilder.setRippleRadius(animValue >= maxDis ? 0 : animValue);
                    }
                    postInvalidate();
                }
            });
            mRippleValueAnimator.start();
        }
    }
}